package com.genntii.examManager.service.impl;

import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.genntii.examManager.common.constant.RoleConstant;
import com.genntii.examManager.common.exception.*;
import com.genntii.examManager.common.properties.JwtProperties;
import com.genntii.examManager.common.security.DBUserManager;
import com.genntii.examManager.common.utils.JwtUtil;
import com.genntii.examManager.domain.entity.Teacher;
import com.genntii.examManager.domain.entity.User;
import com.genntii.examManager.domain.entity.UserSalt;
import com.genntii.examManager.domain.vo.UserLoginVO;
import com.genntii.examManager.mapper.TeacherMapper;
import com.genntii.examManager.mapper.UserMapper;
import com.genntii.examManager.mapper.UserSaltMapper;
import com.genntii.examManager.cache.UserCache;
import com.genntii.examManager.service.UserSecurityService;
import io.jsonwebtoken.impl.DefaultClaims;
import jakarta.annotation.Resource;
import jakarta.mail.internet.InternetAddress;
import jakarta.mail.internet.MimeMessage;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.bcrypt.BCrypt;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.Objects;
import java.util.regex.Pattern;

@Slf4j
@Service
public class UserSecurityServiceImpl extends ServiceImpl<UserMapper, User> implements UserSecurityService {

    @Resource
    private JavaMailSender mailSender;

    @Resource
    private UserMapper userMapper;

    @Resource
    private UserCache userCache;

    @Resource
    private UserSaltMapper userSaltMapper;

    @Value("${spring.mail.username}")
    private String from;

    @Resource
    private JwtProperties jwtProperties;

    @Resource
    private DBUserManager dbUserManager;

    @Resource
    private TeacherMapper teacherMapper;


    @Override
    public UserLoginVO register(String mail, String username, String password, Integer captcha) {
        if (userMapper.usernameExists(username) != 0) {
            throw new UsernameExistsException("该用户名已被使用");
        }

        if (!Objects.equals(captcha, userCache.getCaptcha(mail))) {
            throw new CacheNotFoundException("验证码错误或已超时");
        }

        User userReg = new User();
        userReg.setMail(mail);
        userReg.setUsername(username);
        userReg.setCreateTime(LocalDateTime.now());
        userReg.setUpdateTime(LocalDateTime.now());
        userReg.setRole(RoleConstant.student);
        String salt = BCrypt.gensalt();
        String passwordS = BCrypt.hashpw(password, salt);
        userReg.setSalt(salt);
        userReg.setPassword(passwordS);
        userMapper.insert(userReg);

        userReg.setPassword(passwordS);

        User user = userMapper.selectUserByMail(mail);

        DefaultClaims claims = new DefaultClaims();
        claims.put("id", user.getId());
        claims.put("username", username);
        String token = JwtUtil.createJWT(jwtProperties.getSecretKey(), jwtProperties.getTtl(), claims);

        return UserLoginVO.builder()
                .id(user.getId())
                .username(username)
                .createTime(user.getCreateTime())
                .token(token)
                .role(user.getRole())
                .build();
    }

    @Override
    public UserLoginVO register4t(String mail, String username, String password, Integer captcha) {
        if (userMapper.usernameExists(username) != 0) {
            throw new UsernameExistsException("该用户名已被使用");
        }

        if (!Objects.equals(captcha, userCache.getCaptcha(mail))) {
            throw new CacheNotFoundException("验证码错误或已超时");
        }

        User userReg = new User();
        userReg.setMail(mail);
        userReg.setUsername(username);
        userReg.setCreateTime(LocalDateTime.now());
        userReg.setUpdateTime(LocalDateTime.now());
        userReg.setRole(RoleConstant.teacher);
        userMapper.insert(userReg);
        String salt = BCrypt.gensalt();
        UserSalt userSalt = new UserSalt();
        userSalt.setSalt(salt);
        userSalt.setUserId(userReg.getId());
        userSaltMapper.insert(userSalt);

        Teacher teacher = new Teacher();
        teacher.setUserId(userReg.getId());
        teacher.setName(username);
        teacherMapper.insert(teacher);

        String passwordS = BCrypt.hashpw(password, salt);
        userMapper.setPassword(passwordS, userReg.getId());
        userReg.setPassword(passwordS);

        User user = userMapper.selectUserByMail(mail);

        DefaultClaims claims = new DefaultClaims();
        claims.put("id", user.getId());
        claims.put("username", username);
        String token = JwtUtil.createJWT(jwtProperties.getTeacherSecretKey(), jwtProperties.getTeacherTtl(), claims);

        return UserLoginVO.builder()
                .id(user.getId())
                .username(username)
                .createTime(user.getCreateTime())
                .token(token)
                .role(user.getRole())
                .build();
    }

    @Override
    public void sendMailCaptcha(String mail) {

        if (userMapper.mailExists(mail) != 0) {
            throw new MailExistsException("该邮箱已被使用！");
        }

        //获取MimeMessage对象
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper messageHelper;
        try {
            messageHelper = new MimeMessageHelper(message, true);
            //邮件发送人
            messageHelper.setFrom(from);
            //邮件接收人,设置多个收件人地址
            InternetAddress[] internetAddressTo = InternetAddress.parse(mail);
            messageHelper.setTo(internetAddressTo);
            //messageHelper.setTo(to);
            //邮件主题
            message.setSubject("感谢您的注册");
            //邮件内容，html格式
            messageHelper.setText(String.valueOf(userCache.captchaMailCache(mail)), true);
            //发送
            mailSender.send(message);
            //日志信息
            log.info("邮件已经发送。");
        } catch (Exception e) {
            log.error("邮件发送失败");
            throw new MailSendException("邮件发送失败");
        }
    }

    @Override
    public UserLoginVO login(String loginCredential, String password) {
        String regexPattern = "^[a-zA-Z0-9_-]+@[a-zA-Z0-9_-]+(\\.[a-zA-Z0-9_-]+)+$";

        User user;

        if (Pattern.matches(regexPattern, loginCredential)) {
            if ((user = userMapper.selectUserByMail(loginCredential)) == null) {
                throw new UserNotFoundException("用户不存在");
            }
        } else {
            if ((user = userMapper.selectUserByUser(loginCredential)) == null) {
                throw new UserNotFoundException("用户不存在");
            }
        }

        if (!BCrypt.checkpw(password, user.getPassword())) {
            throw new PasswordErrorException("密码错误");
        }
        UserDetails userDetails = dbUserManager.loadUserByUsername(user.getUsername());

        UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                userDetails, null, userDetails.getAuthorities()
        );

        SecurityContextHolder.getContext().setAuthentication(authToken);

        DefaultClaims claims = new DefaultClaims();
        claims.put("id", user.getId());
        claims.put("username", user.getUsername());
        String token = "token";
        if (Objects.equals(user.getRole(), RoleConstant.student))
            token = JwtUtil.createJWT(jwtProperties.getSecretKey(), jwtProperties.getTtl(), claims);
        else if (Objects.equals(user.getRole(), RoleConstant.teacher)) token = JwtUtil.createJWT(jwtProperties.getTeacherSecretKey(), jwtProperties.getTtl(), claims);

        return UserLoginVO.builder()
                .id(user.getId())
                .username(user.getUsername())
                .nickname(user.getNickname())
                .sex(user.getSex() != null ? (user.getSex() == 1 ? "男" : "女") : null)
                .birthday(user.getBirthday())
                .createTime(user.getCreateTime())
                .token(token)
                .role(user.getRole())
                .avatar(user.getAvatar())
                .build();
    }
}

